package com.xpec.c4.service.module.gateway;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.netty.channel.Channel;

import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.net.XSENetConstant;
import com.xpec.c4.net.XSENetGlobal;
import com.xpec.c4.net.XSENetNettyServer;
import com.xpec.c4.net.XSENetServer;
import com.xpec.c4.net.XSENetSession;
import com.xpec.c4.net.XSENetSessionPool;
import com.xpec.c4.service.common.ServiceInfo;
import com.xpec.c4.service.server.CloseType;
import com.xpec.c4.service.server.Server;
import com.xpec.c4.service.server.ServerOperations;

/**
 * 服务端
 * 
 * @author Bany
 * 
 * @since 2008-8-30 下午04:47:44
 * 
 */

public class GatewayService implements Server 
{

	private static final Log log = LogFactory.getLog(GatewayService.class);
	
	private String ip;

	private int port;

	private String name;
	
	// private GatewayModule module;

	XSENetServer network;
	
	public GatewayService(GatewayModule module, int port, String name) 
	{
		this.port = port;
		this.name = name;
		// this.module = module;

		ServiceInfo.addServer(this);

		/////////////////////////////////////////////////////////////////////
		// network
		
		network = XSENetServer.createServer(XSENetGlobal.mLibType,
				XSENetConstant.PROTOCOLTYPE_TCP);
		network.setName(name);
		network.setGatewayModule(module);
		network.setHandleMode(XSENetConstant.HANDLE_GATEWAYMODE);
		network.bind(port);

		/////////////////////////////////////////////////////////////////////
		
		//JobExecutor.scheduleAtFixedRate(new FlushMessage(), 0, 250, TimeUnit.MILLISECONDS);
	}

	public GatewayService(GatewayModule module, String ip, int port, String name) 
	{
		this.setIp(ip);
		this.port = port;
		this.name = name;
		// this.module = module;

		ServiceInfo.addServer(this);

		/////////////////////////////////////////////////////////////////////
		// network
		
		network = XSENetServer.createServer(XSENetGlobal.mLibType, XSENetConstant.PROTOCOLTYPE_TCP);
		network.setName(name);
		network.setGatewayModule(module);
		network.setHandleMode(XSENetConstant.HANDLE_GATEWAYMODE);
		network.bind(ip, port);

		/////////////////////////////////////////////////////////////////////
		
		//JobExecutor.schedule(new FlushMessage(), 250);
	}

	public void start() throws IOException 
	{
		for (int i = 0; i < 6; i++) 
		{
			try 
			{
				network.start();
			} 
			catch (Exception e) 
			{
				log.error("start server fail",e);
				try 
				{
					Thread.sleep(10000);
				} 
				catch (InterruptedException e1) {
				}
				continue;
			}
			
			if( !network.isStarted() )
			{
				log.error("start server fail");
				
				try 
				{
					Thread.sleep(10000);
				} 
				catch (InterruptedException e1) {}
				
				continue;
			}
			break;
		}

		if( !network.isStarted() ) 
		{
			log.error("=== can not start server! ===");
			throw new Error();
		}
		log.info("Listening on port " + port);
	}

	/**
	 * 
	 */
	public void kickAllConnect(CloseType closeType, GatewayModule module) {

		/*
		 * 原本的踢法會先斷掉session, 再斷channel，但是不正常的連線會有...有channel而沒有session的情況.
		 * 導致有些連線踢不掉
		 */
		
		// 先踢掉有正常連線的		
		List<XSENetSession> allSession = new ArrayList<XSENetSession>(
				ServiceInfo.getAllSession());

		for (XSENetSession session : allSession) {
			if (session != null) {
				try {
					GUID sessionID = session.getID();
					log.info("force close session:" + sessionID);

					// rowan: close each player session
					ServerOperations.sessionClose(sessionID, closeType, module);
					Thread.sleep(10);
				} catch (Exception e) {
					log.error("Stop Listening on port " + port + "is error!!!",
							e);
				}
			}
		}				
		
		// 再踢掉有連線但是沒xseNetSession的
		Collection<Channel> nullChannel = XSENetSessionPool.getNullSessions();
		
		if(nullChannel != null && nullChannel.size() > 0){
			
			for(Channel ch: nullChannel){
				if(ch != null){
					// 有建立連線, 還沒正常驗證的就直接斷線
					try {
						ch.disconnect();
					} catch (Exception e) {
						log.error("disconnect error!", e);
					}
				}
			}
		}
		
		
/*		
		if( this.network instanceof XSENetNettyServer)
		{			
			Set<Channel> allKey = XSENetSessionPool.getAllSessionKey();			
			
			if(allKey != null && allKey.size() > 0){
				
				for(Channel ch: allKey){					
					if(ch != null){
						XSENetSession session = XSENetSessionPool.getSession(ch);
						if (session != null) {
							try {
								GUID sessionID = session.getID();

								if (sessionID != null) {
									
									if(log.isInfoEnabled()){
										log.info("force close session:" + sessionID);
									}

									// rowan: close each player session
									ServerOperations.sessionClose(sessionID,
											CloseType.KICK_BY_GM);
									Thread.sleep(10);
								}else{
									// 有建立連線, 還沒正常驗證的就直接斷線
									try {
										ch.disconnect();
									} catch (Exception e) {
										log.error("disconnect error!", e);
									}				
								}
								
							} catch (Exception e) {
								log.error("Stop Listening on port " + port
										+ "is error!!!", e);
							}
						}
					}
				}
			}
		}
		
*/		

		
	}

	@Override
	public void stop() 
	{
		//[0]stop accepting new session
		network.allowNewConnection(false);
		
		//[1]kick existing player
		// 停止服務(listen) 不用踢掉玩家
//		kickAllConnect();
		
//		try 
//		{
//			Thread.sleep(1000);
//		} 
//		catch (Exception e)	{
//			log.error("Stop Listening on port " + port + "is error!!!", e);
//		}

		//[3]close entire network layer
		network.close();
		if(log.isInfoEnabled()){
			log.info("Stop Listening on port " + port);
		}
		
	}

	/**
	 * 获得端口
	 */
	public int getPort() 
	{
		return port;
	}

	@Override
	public int getAcceptedCount() 
	{
		//
		if( this.network instanceof XSENetNettyServer)
		{
			return ((XSENetNettyServer)this.network).getConnectCount();
		}
		else
			return ServiceInfo.getSessions().size();
	}

	public int getRobotCount() {
		if (this.network instanceof XSENetNettyServer) {
			return ((XSENetNettyServer) this.network).getRobotCount();
		}

		return 0;
	}

	/**
	 * 
	 * @return
	 */
	public int getHistoryConnectCount() 
	{
		if( this.network instanceof XSENetNettyServer)
		{
			return ((XSENetNettyServer)this.network).getHistoryConnectCount();
		}
		return 0;
	}
	
	@Override
	public void addActionClass(Class<?> clazz) 
	{
	}

	public String getName() 
	{
		return name;
	}

	public Integer getInputBps() {
		return network.getMeter().getInputBps();
	}

	public Integer getOutputPps() {
		return network.getMeter().getOutputPps();
	}

	public Integer getOutputBps() {
		return network.getMeter().getOutputBps();
	}

	public Integer getInputPps() {
		return network.getMeter().getInputPps();
	}
	
	/**
	 * 
	 * @param stat
	 * @return
	 * @throws IOException
	 */
	public boolean enableService(boolean stat) throws IOException{
		if (network != null) {
			boolean oldStat = network.isNewConnectionAllowed();
			network.allowNewConnection(stat);
			
			// 如果狀態與原本不同再處理指定的狀態
			if(oldStat != stat){
				if(stat){					
					this.start();
				}else{
					this.stop();
				}				
			}
			
			return oldStat;
		}
		return false;
	}

	public boolean isNewConnectionAllowed() {
		if (network != null) {
			return network.isNewConnectionAllowed();
		}
		return false;
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}	
}

